package com.demo2do.fms.admin.web.controller.supplier.appraisal;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.entity.page.Page;
import com.demo2do.core.entity.result.HttpResult;
import com.demo2do.core.utils.CollectionUtils;
import com.demo2do.core.web.interceptor.MenuSetting;
import com.demo2do.core.web.resolver.Preloading;
import com.demo2do.core.web.utils.WebUtils;
import com.demo2do.fms.admin.entity.search.supplier.AppraisalSearch;
import com.demo2do.fms.admin.entity.security.Login;
import com.demo2do.fms.admin.service.DataService;
import com.demo2do.fms.admin.service.supplier.AppraisalResultService;
import com.demo2do.fms.admin.service.supplier.AppraisalService;
import com.demo2do.fms.admin.service.supplier.AppraisalTemplateService;
import com.demo2do.fms.admin.service.supplier.SupplierService;
import com.demo2do.fms.admin.web.resolver.Secure;
import com.demo2do.fms.admin.web.view.ExcelTemplateView;
import com.demo2do.fms.entity.appraisal.Appraisal;
import com.demo2do.fms.entity.appraisal.AppraisalResultItem;
import com.demo2do.fms.entity.appraisal.AppraisalResult;
import com.demo2do.fms.entity.appraisal.AppraisalTemplate;
import com.demo2do.fms.entity.supplier.common.AuditStatus;
import com.demo2do.fms.entity.supplier.common.Supplier;
import com.demo2do.fms.entity.supplier.common.Type;
import com.demo2do.fms.entity.vendor.Vendor;

/**
 * 绩效考核管理
 * 
 * Created by zhonghui on 2017/7/3.
 * @author Ark
 * 
 */
@Controller
@RequestMapping("/appraisals")
@MenuSetting("menu-supplier")
public class AppraisalController {
    
    private static final Logger logger = LoggerFactory.getLogger(AppraisalController.class);
    
    @Autowired
    private AppraisalService appraisalSerive;
    
    @Autowired
    private AppraisalTemplateService appraisalTemplateService;
    
    @Autowired
    private AppraisalResultService appraisalResultSerive;
    
    @Autowired
    private SupplierService supplierService;
    
    @Autowired
    @Qualifier("dataService")
    private DataService<Vendor> vendorService;

    /**
     * list
     * 
     * @param page
     * @return
     */
    @RequestMapping(value = "", method = RequestMethod.GET)
    @MenuSetting("submenu-performance-appraisal-management")
    public ModelAndView list(@Secure Login login, Page page) {

        ModelAndView modelAndView = new ModelAndView("supplier/appraisal/appraisal/appraisal-list");
        
        int totals = appraisalSerive.count(login);
        if (totals > 0) {

            List<Appraisal> appraisals = appraisalSerive.list(login, page.with(totals));

            modelAndView.addObject("appraisals", appraisals);
            modelAndView.addObject("page", page);
            
        }

        return modelAndView;
        
    }
    
    /**
     * search
     *
     * @return
     */
    @RequestMapping(value = "/search", method = RequestMethod.GET)
    public ModelAndView search() {
        ModelAndView modelAndView = new ModelAndView("supplier/appraisal/appraisal/appraisal-search");
        return modelAndView;
    }

    /**
     * onSearch
     * 
     * @param request
     * @param search
     * @param page
     * @return
     */
    @RequestMapping(value = "", method = RequestMethod.GET, params = "filter")
    @MenuSetting("submenu-performance-appraisal-management")
    public ModelAndView onSearch(AppraisalSearch search, @Secure Login login,
                                 HttpServletRequest request, Page page) {

        ModelAndView modelAndView = new ModelAndView("supplier/appraisal/appraisal/appraisal-list");
        
        int totals = appraisalSerive.count(search, login);
        if (totals > 0) {
            
            List<Appraisal> appraisals = appraisalSerive.list(search, login, page.with(totals));
            modelAndView.addObject("appraisals", appraisals);
            
            modelAndView.addObject("page", page);
            modelAndView.addObject("queryString", WebUtils.extractQueryString(request, "page", "filter"));
            
        }

        return modelAndView;
        
    }

    /**
     * view
     * 
     * @param id
     * @return
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @MenuSetting("submenu-performance-appraisal-management")
    public ModelAndView view(@PathVariable("id") Long id) {

        ModelAndView modelAndView = new ModelAndView("supplier/appraisal/appraisal/appraisal-view");
        
        // 1. load appraisal
        Appraisal appraisal = appraisalSerive.load(Appraisal.class, id);
        modelAndView.addObject("appraisal", appraisal);
        
        // 2. list appraisalResult
        List<AppraisalResult> appraisalResults = appraisalResultSerive.list(appraisal);
        modelAndView.addObject("appraisalResults", appraisalResults);

        // 3. construct AppraisalResultItem Map
        List<AppraisalResultItem> appraisalResultItems = appraisalResultSerive.listItem(appraisal);
        Map<String, List<AppraisalResultItem>> appraisalResultItemMap = CollectionUtils.constructMapValues(appraisalResultItems, "result.id");
        modelAndView.addObject("appraisalResultItemMap", appraisalResultItemMap);

        return modelAndView;
        
    }

    /**
     * create panel
     *
     * @return
     */
    @RequestMapping(value = "/create", method = RequestMethod.GET)
    @MenuSetting("submenu-performance-appraisal-management")
    public ModelAndView create(@Secure Login login) {

        ModelAndView modelAndView = new ModelAndView("supplier/appraisal/appraisal/appraisal-create");
        
        List<AppraisalTemplate> templates = appraisalTemplateService.list(login);
        modelAndView.addObject("templates", templates);

        return modelAndView;
        
    }
    
    /**
     * create
     * 
     * @param login
     * @param appraisal
     * @return
     */
    @RequestMapping(value = "", method = RequestMethod.POST , produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @MenuSetting("submenu-performance-appraisal-management")
    public @ResponseBody HttpResult onCreate(@Secure Login login, Appraisal appraisal) {
        
        HttpResult httpResult = new HttpResult();
        
        try {

            appraisalSerive.create(appraisal, login);

            httpResult.success().message("创建成功");

        } catch (Exception e) {
            logger.error("#onCreate() - create occur exception [{}]", e);
            httpResult.fail("500").message("创建失败！" + e.getMessage());
        }
        
        return httpResult;
        
    }
    
    /**
     * edit panel
     * 
     * @param id
     * @return
     */
    @RequestMapping(value = "/{id}/edit", method = RequestMethod.GET)
    @MenuSetting("submenu-performance-appraisal-management")
    public ModelAndView edit(@PathVariable("id") Long id) {

        ModelAndView modelAndView = new ModelAndView("supplier/appraisal/appraisal/appraisal-edit");
        
        Appraisal appraisal = appraisalSerive.load(Appraisal.class, id);
        
        modelAndView.addObject("appraisal", appraisal);

        return modelAndView;
        
    }
    
    /**
     * edit
     * 
     * @param appraisal
     * @return
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.PATCH , produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @MenuSetting("submenu-performance-appraisal-management")
    public @ResponseBody HttpResult onEdit(@Preloading("appraisalId") Appraisal appraisal, @Secure Login operator) {

        HttpResult httpResult = new HttpResult();

        try {

            appraisalSerive.edit(appraisal, operator);

            httpResult.success().message("编辑成功");

        } catch (Exception e) {
            logger.error("#onEdit() - edit appraisal occur exception [{}]", e);
            httpResult.fail("500").message("编辑失败！" + e.getMessage());
        }

        return httpResult;

    }
    
    /**
     * delete panel
     * 
     * @param id
     * @return
     */
    @RequestMapping(value = "/{id}/delete", method = RequestMethod.GET)
    @MenuSetting("submenu-performance-appraisal-management")
    public ModelAndView delete(@PathVariable("id") Long id) {

        ModelAndView modelAndView = new ModelAndView("supplier/appraisal/appraisal/appraisal-delete");
        
        modelAndView.addObject("id", id);

        return modelAndView;
        
    }
    
    /**
     * delete
     * 
     * @param appraisal
     * @return
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE , produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @MenuSetting("submenu-performance-appraisal-management")
    public @ResponseBody HttpResult onDelete(@PathVariable("id") Long id, @Secure(property = "id") Long operator) {

        HttpResult httpResult = new HttpResult();

        try {

            Appraisal appraisal = appraisalSerive.load(Appraisal.class, id);
            appraisalSerive.delete(appraisal, operator);
            
            httpResult.success().message("删除成功");

        } catch (Exception e) {
            logger.error("#onDelete() - edit appraisal occur exception [{}]", e);
            httpResult.fail("500").message("删除失败！" + e.getMessage());
        }

        return httpResult;

    }
    
    /**
     * add supplier or vendor
     * 
     * @param appraisalId
     * @return
     */
    @RequestMapping(value = "/{appraisalId}/results/create", method = RequestMethod.GET)
    @MenuSetting("submenu-performance-appraisal-management")
    public ModelAndView addSupplier(@PathVariable("appraisalId") Long appraisalId, @Secure Login login) {

        ModelAndView modelAndView = new ModelAndView("supplier/appraisal/appraisal-result/appraisal-result-create");
        
        // 1. load appraisal
        Appraisal appraisal = appraisalSerive.load(Appraisal.class, appraisalId);
        modelAndView.addObject("appraisal", appraisal);
        
        // 2. Determine appraisal target
        if(appraisal.getTarget().isVendor()) {          // appraisal target is vendor
            
            List<Vendor> vendors = vendorService.listAll(Vendor.class);
            modelAndView.addObject("suppliers", vendors);
            
        } else {                                        // appraisal target is trans/ware
            
            List<AuditStatus> status = Arrays.asList(AuditStatus.QUALIFIED, AuditStatus.ONE_LEVEL_RECTIFY, AuditStatus.TWO_LEVEL_RECTIFY, AuditStatus.UNITE_RECTIFY);
            List<Supplier> suppliers = supplierService.list(Type.aliasOf(appraisal.getTarget().getName()), status, login);
            modelAndView.addObject("suppliers", suppliers);
            
        }
        
        // 3. get checked_suppliers
        List<String> checkedSuppliers = appraisalResultSerive.listTarget(appraisal);
        modelAndView.addObject("checkedSuppliers", checkedSuppliers);
        
        return modelAndView;
    }
    
    /**
     * on add supplier
     * 
     * @param appraisalId
     * @param supplierIds
     * @return
     */
    @RequestMapping(value = "/{appraisalId}/results", method = RequestMethod.POST , produces = MediaType.APPLICATION_JSON_UTF8_VALUE, params = {"target=supplier"})
    public @ResponseBody HttpResult onAddSupplier(@PathVariable("appraisalId") Long appraisalId,
                                                  @RequestParam("supplierIds") List<Long> supplierIds,
                                                  @Secure(property = "id") Long operator) {
        
        HttpResult httpResult = new HttpResult();
        
        try {
            
            Appraisal appraisal = appraisalSerive.load(Appraisal.class, appraisalId);
            
            for(Long supplierId : supplierIds) {
                Supplier supplier = supplierService.load(Supplier.class, supplierId);
                appraisalResultSerive.create(supplier, appraisal, operator);
            }
            
            httpResult.success().message("添加供方成功");
           
       } catch (Exception e) {
           logger.error("#onAddSupplier - add supplier failed, exception=[{}]", e);
           httpResult.fail("500").message("添加供方失败！" + e.getMessage());
       }
        
        return httpResult;
        
    }
    
    /**
     * on add vendor
     * 
     * @param appraisalId
     * @param vendorIds
     * @return
     */
    @RequestMapping(value = "/{appraisalId}/results", method = RequestMethod.POST , produces = MediaType.APPLICATION_JSON_UTF8_VALUE, params = {"target=vendor"})
    public @ResponseBody HttpResult onAddVendor(@PathVariable("appraisalId") Long appraisalId,
                                                @RequestParam("supplierIds") List<String> vendorIds,
                                                @Secure(property = "id") Long operator) {
        
        HttpResult httpResult = new HttpResult();
        
        try {
            
            Appraisal appraisal = appraisalSerive.load(Appraisal.class, appraisalId);
            
            for(String vendorId : vendorIds) {
                Vendor vendor = vendorService.load(Vendor.class, vendorId);
                appraisalResultSerive.create(vendor, appraisal, operator);
            }
            
            httpResult.success().message("添加供方成功");
           
       } catch (Exception e) {
           logger.error("#onAddSupplier - add supplier failed, exception=[{}]", e);
           httpResult.fail("500").message("添加供方失败！" + e.getMessage());
       }
        
        return httpResult;
        
    }
    
    /**
     * rate panel
     * 
     * @param resultId
     * @param id
     * @return
     */
    @RequestMapping(value = "/{appraisalId}/results/{resultId}/rate", method = RequestMethod.GET)
    public ModelAndView rate(@PathVariable("appraisalId") Long appraisalId, @PathVariable("resultId") Long resultId) {
    
        ModelAndView modelAndView = new ModelAndView("supplier/appraisal/appraisal/appraisal-rate");
        
        AppraisalResult appraisalResult = appraisalResultSerive.load(AppraisalResult.class, resultId);
        List<AppraisalResultItem> appraisalResultItems = appraisalResultSerive.listItem(appraisalResult);
        modelAndView.addObject("appraisalResultItems", appraisalResultItems);
        
        modelAndView.addObject("appraisalId", appraisalId);
        modelAndView.addObject("resultId", resultId);
    
        return modelAndView;
        
    }

    /**
     * rate
     * 
     * @param resultId
     * @param itemResults
     * @param operator
     * @return
     */
    @RequestMapping(value = "/{appraisalId}/results/{resultId}/rate", method = RequestMethod.PATCH , produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public @ResponseBody HttpResult onRate(@PathVariable("resultId") Long resultId,
                                           @RequestParam("itemResults") List<String> itemResults,
                                           @Secure Login operator) {

        HttpResult httpResult = new HttpResult();

        try {

            AppraisalResult appraisalResult = appraisalResultSerive.load(AppraisalResult.class, resultId);
            appraisalResultSerive.rate(itemResults, appraisalResult, operator);

            httpResult.success().message("评分成功");

        } catch (BusinessException e) {
            logger.error("#onRate() - rate appraisal occur businession exception [{}]", e);
            httpResult.fail("500").message(e.getMessage());
        } catch (Exception e) {
            logger.error("#onRate() - rate appraisal occur system exception [{}]", e);
            httpResult.fail("500").message("评分失败");
        }

        return httpResult;
        
    }

    /**
     * rate panel
     * 
     * @param resultId
     * @param id
     * @return
     */
    @RequestMapping(value = "/{appraisalId}/results/{resultId}/delete", method = RequestMethod.GET)
    public ModelAndView deleteResult(@PathVariable("appraisalId") Long appraisalId, @PathVariable("resultId") Long resultId) {
    
        ModelAndView modelAndView = new ModelAndView("supplier/appraisal/appraisal-result/appraisal-result-delete");
        
        modelAndView.addObject("appraisalId", appraisalId);
        
        modelAndView.addObject("resultId", resultId);
        
        return modelAndView;
    }

    /**
     * rate
     * 
     * @param resultId
     * @param itemResults
     * @param operator
     * @return
     */
    @RequestMapping(value = "/{appraisalId}/results/{resultId}/delete", method = RequestMethod.PATCH , produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public @ResponseBody HttpResult onDeleteResult(@PathVariable("resultId") Long resultId,
                                                   @PathVariable("appraisalId") Long appraisalId,
                                                   @Secure Login operator) {

        HttpResult httpResult = new HttpResult();

        try {
            appraisalResultSerive.delete(resultId, operator.getId());
            
            httpResult.success().message("删除成功");

        } catch (BusinessException e) {
            logger.error("#onDeleteResult() - delete appraisal result occur businession exception [{}]", e);
            httpResult.fail("500").message(e.getMessage());
        } catch (Exception e) {
            logger.error("#onDeleteResult() - delete appraisal resutl occur system exception [{}]", e);
            httpResult.fail("500").message("删除失败");
        }

        return httpResult;
        
    }
        
    
    /**
     * sign panel
     * 
     * @param appraisalId
     * @return
     */
    @RequestMapping(value = "/{appraisalId}/sign", method = RequestMethod.GET)
    @MenuSetting("submenu-performance-appraisal-management")
    public ModelAndView sign(@PathVariable("appraisalId") Long appraisalId) {

        ModelAndView modelAndView = new ModelAndView("supplier/appraisal/appraisal/appraisal-sign");
        
        modelAndView.addObject("appraisalId", appraisalId);

        return modelAndView;
        
    }
    
    /**
     * sign
     * 
     * @param appraisalId
     * @param operator
     * @return
     */
    @RequestMapping(value = "/{appraisalId}/sign", method = RequestMethod.PATCH , produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @MenuSetting("submenu-performance-appraisal-management")
    public @ResponseBody HttpResult onSign(@PathVariable("appraisalId") Long appraisalId, @Secure(property = "id") Long operator) {

        HttpResult httpResult = new HttpResult();

        try {

            Appraisal appraisal = appraisalSerive.load(Appraisal.class, appraisalId);
            appraisalSerive.sign(appraisal, operator);

            httpResult.success().message("标记成功");

        } catch (Exception e) {
            logger.error("#onSign() - sign appraisal occur exception [{}]", e);
            httpResult.fail("500").message("标记失败！" + e.getMessage());
        }

        return httpResult;
    }
    
    /**
     * export panel
     * 
     * @param appraisalId
     * @return
     */
    @RequestMapping(value = "/{appraisalId}/export", method = RequestMethod.GET)
    public ModelAndView export(@PathVariable("appraisalId") Long appraisalId) {

        ModelAndView modelAndView = new ModelAndView("supplier/appraisal/appraisal/appraisal-export");
        
        modelAndView.addObject("appraisalId", appraisalId);

        return modelAndView;
        
    }
    
    /**
     * export
     * 
     * @param appraisalId
     * @return
     */
    @RequestMapping(value = "/{appraisalId}/export", method = RequestMethod.POST)
    public ModelAndView onExport(@PathVariable("appraisalId") Long appraisalId) {

        ModelAndView modelAndView = new ModelAndView(new ExcelTemplateView("supplier/appraisal-export.xlsx"));
        
        // 1. load appraisal
        Appraisal appraisal = appraisalSerive.load(Appraisal.class, appraisalId);
        modelAndView.addObject("appraisal", appraisal);
        
        // 2. list appraisalResult
        List<AppraisalResult> appraisalResults = appraisalResultSerive.list(appraisal);
        modelAndView.addObject("appraisalResults", appraisalResults);

        // 3. construct AppraisalResultItem Map
        List<AppraisalResultItem> appraisalResultItems = appraisalResultSerive.listItem(appraisal);
        Map<String, List<AppraisalResultItem>> appraisalResultItemMap = CollectionUtils.constructMapValues(appraisalResultItems, "result.id");
        modelAndView.addObject("appraisalResultItemMap", appraisalResultItemMap);

        // 4. list item of one appraisal_result
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(appraisalResults)) {
            List<AppraisalResultItem> headResultItems = appraisalResultSerive.listItem(appraisalResults.get(0));
            modelAndView.addObject("headResultItems", headResultItems);
        }
        
        return modelAndView;
        
    }
    
}
